home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 November: Tool Chest / Dev.CD Nov 96 TC / Dev.CD Nov 96 TC.toast / Sample Code / Interapplication Communication / MenuScripter 4.0 / Sources / MSAETextUtils.c < prev    next >
Encoding:
Text File  |  1996-07-09  |  17.9 KB  |  767 lines  |  [TEXT/CWIE]

  1. // MSAETextUtils.c
  2. //
  3. // Original version by Jon Lansdell and Nigel Humphreys.
  4. // 4.0 and 3.1 updates by Greg Sutton.
  5. // ©Apple Computer Inc 1996, all rights reserved.
  6.  
  7. /*
  8.     14-Nov-95 : GS : Removed reliance on compiler setting local variable to zero
  9.                         in GetInsertDescFromInsertHere().
  10. */
  11.  
  12. #include "MSAETextUtils.h"
  13.  
  14. #include "MSAEUtils.h"
  15. #include "MSWindow.h"        // for DPtrFromWindowPtr()
  16. #include "MSAERecording.h"
  17.  
  18.  
  19. #include <AEPackObject.h>
  20.  
  21.  
  22.  
  23. // ----------------------------------------------------------------------------------
  24. //    Name:    PutStyledTextFromDescIntoTEHandle
  25. //    Purpose: Takes the text in an AEDesc containing typeIntlText and puts it in
  26. //             a styled text edit record at the current insertion point.
  27. //                     Looks for typeIntlText, typeStyledText, typeChar in that order.
  28. // ----------------------------------------------------------------------------------
  29.  
  30. OSErr    PutStyledTextFromDescIntoTEHandle(const AEDesc *sourceTextDesc, TEHandle theHTE)
  31. {
  32.     AEDesc styledTextDesc = { typeNull, NULL };
  33.     AEDesc textStyleDesc = { typeNull, NULL };
  34.     AEDesc rawTextDesc = { typeNull, NULL };
  35.     OSErr  myErr;
  36.     
  37.     //    Coerce to an AERecord and then extract the parts of the
  38.     //    styled text - works for typeIntlText, typeStyledText
  39.  
  40.     myErr = AECoerceDesc(sourceTextDesc, typeAERecord, &styledTextDesc);
  41.     
  42.     if (noErr == myErr)
  43.     {        
  44.         myErr = AEGetKeyDesc(&styledTextDesc,  keyAEText,
  45.                                             typeChar, &rawTextDesc);
  46.                                                  
  47.         myErr = AEGetKeyDesc(&styledTextDesc,  keyAEStyles,
  48.                                             typeScrapStyles, &textStyleDesc);
  49.     }
  50.     else
  51.     {
  52.         myErr = AECoerceDesc(sourceTextDesc, typeChar, &rawTextDesc);
  53.         
  54.         textStyleDesc.dataHandle = NULL; // so that TEStylInsert acts like TEInsert                
  55.     }
  56.             
  57.     HLock((Handle)rawTextDesc.dataHandle);
  58.     
  59.     TEDelete(theHTE);                    // Insert over current selection
  60.     TEStylInsert((const void *) (*rawTextDesc.dataHandle),
  61.                                          GetHandleSize(rawTextDesc.dataHandle),
  62.                                              (StScrpHandle) textStyleDesc.dataHandle,
  63.                                                  theHTE);
  64.                              
  65.     HUnlock((Handle)rawTextDesc.dataHandle);
  66.     
  67.     (void)AEDisposeDesc(&textStyleDesc);
  68.     (void)AEDisposeDesc(&rawTextDesc);
  69.     (void)AEDisposeDesc(&styledTextDesc);
  70.         
  71.     return(myErr);
  72. }
  73.  
  74.  
  75. TEHandle    TEHandleFromWindow(WindowPtr theWindow)
  76. {
  77.     DPtr        docPtr;
  78.     TEHandle    result = NULL;
  79.     
  80.     if (! theWindow)
  81.         return(NULL);
  82.     
  83.     docPtr = DPtrFromWindowPtr(theWindow);
  84.     
  85.     if (docPtr)
  86.         result = docPtr->theText;
  87.         
  88.     return(result);
  89. }
  90.  
  91. TEHandle    TEHandleFromTextToken(TextToken* aToken)
  92. {
  93.     if (! aToken)
  94.         return(NULL);
  95.         
  96.     return(TEHandleFromWindow(aToken->tokenWindow));
  97. }
  98.  
  99.  
  100. OSErr    GetInsertDescFromInsertHere(AEDesc* insertHereDesc, AEDesc* insertDesc, DescType* insertType)
  101. {
  102.     AEDesc        insertRec = {typeNull, NULL},
  103.                 objectSpec = {typeNull, NULL};
  104.     DescType    returnedType;
  105.     Size        actualSize;
  106.     OSErr        err = noErr;
  107.  
  108.      switch (insertHereDesc->descriptorType)
  109.      {
  110.          case typeInsertionLoc:
  111.              err = AECoerceDesc(insertHereDesc, typeAERecord, &insertRec);
  112.              if (noErr != err) goto done;
  113.              
  114.              err = AEGetKeyPtr(&insertRec, keyAEPosition, typeEnumeration, &returnedType,
  115.                                          (Ptr)insertType, sizeof(insertType), &actualSize);
  116.              if (noErr != err) goto done;
  117.  
  118.             err = AEGetKeyDesc(&insertRec, keyAEObject, typeWildCard, &objectSpec);
  119.             if (objectSpec.descriptorType != typeNull)
  120.             {
  121.                 err = AEResolve(&objectSpec, kAEIDoMinimum, insertDesc);
  122.                 if (err != noErr) goto done;
  123.             }
  124.              break;
  125.      
  126.          case typeObjectSpecifier:
  127.              err = AEResolve(insertHereDesc, kAEIDoMinimum, insertDesc);
  128.              if (noErr != err) goto done;
  129.              *insertType = insertDesc->descriptorType;
  130.              break;
  131.              
  132.          case typeNull:                    // No insertion location given
  133.              *insertType = typeNull;
  134.              break;
  135.              
  136.          case typeType:
  137.              *insertType = *(DescType *)*insertHereDesc->dataHandle;
  138.              break;
  139.              
  140.          default:                        // Just copy the descriptor
  141.              err = AEDuplicateDesc(insertHereDesc, insertDesc);
  142.              if (noErr != err) goto done;
  143.              *insertType = insertDesc->descriptorType;
  144.      }
  145.      
  146.  done:
  147.      if (insertRec.dataHandle)
  148.          AEDisposeDesc(&insertRec);
  149.      if (objectSpec.dataHandle)
  150.          AEDisposeDesc(&objectSpec);
  151.      
  152.      return(err);
  153. }
  154.  
  155. // This routine returns an enumerated type describing the relative position
  156. // of one TextToken to another.
  157.  
  158. TokenWithinType    TokenWithinToken(TextToken* container, TextToken* token, short* numPartial)
  159. {
  160.     TokenWithinType        result;
  161.  
  162.     if (token->tokenOffset + token->tokenLength < container->tokenOffset)
  163.         result = kTokenBefore;
  164.     else if (container->tokenOffset + container->tokenLength < token->tokenOffset)
  165.         result = kTokenAfter;
  166.     else if (token->tokenOffset >= container->tokenOffset
  167.                 && token->tokenOffset + token->tokenLength <= container->tokenOffset + container->tokenLength)
  168.         result = kTokenWithin;
  169.     else if (token->tokenOffset < container->tokenOffset)
  170.     {
  171.         result = kTokenPartialBefore;
  172.         if (numPartial)
  173.             *numPartial = token->tokenOffset + token->tokenLength - container->tokenOffset;
  174.     }
  175.     else
  176.     {
  177.         result = kTokenPartialAfter;
  178.         if (numPartial)
  179.             *numPartial = container->tokenOffset + container->tokenLength - token->tokenOffset;
  180.     }
  181.     
  182.     return(result);
  183. }
  184.  
  185.  
  186. OSErr    TextTokenFromDocumentToken(WindowToken* theWindowToken, TextToken* theTextToken)
  187. {
  188.     DPtr        docPtr;
  189.  
  190.     docPtr = DPtrFromWindowPtr(theWindowToken->tokenWindow);
  191.  
  192.     if (! docPtr)
  193.         return(errAENoSuchObject);
  194.             // Create our text token
  195.     theTextToken->tokenWindow = theWindowToken->tokenWindow;    
  196.     theTextToken->tokenOffset = 1;                                // Start at 1
  197.     theTextToken->tokenLength = (**docPtr->theText).teLength;    // through whole length
  198.     
  199.     return(noErr);
  200. }
  201.  
  202.  
  203. OSErr    TextTokenFromDocumentDesc(AEDesc* windowDesc, TextToken* theToken)
  204. {
  205.     AEDesc            aDesc = {typeNull, NULL};
  206.     WindowToken        aWindowToken;
  207.     Size            actualSize;
  208.     OSErr            err;
  209.     
  210.     err = AECoerceDesc(windowDesc, typeMyDocument, &aDesc);
  211.     if (noErr != err) goto done;
  212.         
  213.     GetRawDataFromDescriptor(&aDesc, (Ptr)&aWindowToken,
  214.                                     sizeof(aWindowToken), &actualSize);
  215.  
  216.     err = TextTokenFromDocumentToken(&aWindowToken, theToken);
  217.     
  218. done:    
  219.     (void)AEDisposeDesc(&aDesc);
  220.  
  221.     return(err);
  222. }
  223.  
  224.  
  225. OSErr    TextDescFromDocumentToken(WindowToken* theWindowToken, AEDesc* textDesc)
  226. {
  227.     TextToken    aToken;
  228.     OSErr        err;
  229.     
  230.     err = TextTokenFromDocumentToken(theWindowToken, &aToken);
  231.     if (noErr != err) goto done;
  232.     
  233.     err = AECreateDesc(typeMyText, (Ptr)&aToken, sizeof(aToken), textDesc);
  234.  
  235. done:
  236.     return(err);
  237. }
  238.  
  239.  
  240. OSErr    TextDescFromDocumentDesc(AEDesc* windowDesc, AEDesc* textDesc)
  241. {
  242.     TextToken    aToken;
  243.     OSErr        err;
  244.     
  245.     err = TextTokenFromDocumentDesc(windowDesc, &aToken);
  246.     if (noErr != err) goto done;
  247.     
  248.     err = AECreateDesc(typeMyText, (Ptr)&aToken, sizeof(aToken), textDesc);
  249.  
  250. done:
  251.     return(err);
  252. }
  253.  
  254.  
  255. void MoveToNonSpace(short *start, short limit, charsHandle myChars)
  256.     // Treats space, comma, full stop, ; and : as space chars
  257.     short x;
  258.  
  259.     while (*start <= limit) {
  260.       x = (**myChars)[*start];
  261.         if (IsWhiteSpace(x))
  262.             (*start) +=1;
  263.         else
  264.             return;
  265.     }
  266. }
  267.     
  268. void    MoveToSpace(short *start, short limit, charsHandle myChars)
  269.     // Treats space,comma, full stop, ; and : as space chars
  270.     short x;
  271.     
  272.     while (*start <= limit)
  273.     {
  274.         x = (**myChars)[*start];
  275.         if (! IsWhiteSpace(x))
  276.             (*start)++;
  277.         else
  278.             return;
  279.     }
  280. }
  281.  
  282. void    MoveToEndOfParagraph(short *start, short limit, charsHandle myChars)
  283.     //    Treats CR as end of paragraph
  284.     short x;
  285.     
  286.     while (*start <= limit)
  287.     {
  288.         x = (**myChars)[*start];
  289.         if (! IsParagraphDelimiter(x))        // had x != CR
  290.             (*start)++;
  291.         else
  292.             return;
  293.     }
  294. }
  295.  
  296.  
  297. // This routine counts the given elementType between startAt and 
  298.  
  299. OSErr    CountTextElements(TEHandle inTextHandle, short startAt,
  300.                                 short forHowManyChars, DescType elementType, short* result)
  301. {
  302.     charsHandle    theChars;
  303.     short       limit,
  304.                 start;
  305.     OSErr        err = noErr;
  306.  
  307.     switch (elementType)
  308.     {
  309.         case cInsertionPoint:    // Always one more insertion location than characters
  310.             *result = forHowManyChars + 1;
  311.             break;
  312.             
  313.         case cChar:            // Easy
  314.             *result = forHowManyChars;
  315.             break;
  316.             
  317.         case cText:    
  318.             *result = 1;
  319.             break;
  320.         
  321.         case cWord:            // Cycle through - counting
  322.         case cParagraph:
  323.             theChars = (charsHandle)(**inTextHandle).hText;
  324.             start = startAt - 1;                    // Convert to zero based
  325.             limit = start + forHowManyChars - 1;    // when passed one based
  326.             *result    = 0;
  327.             MoveToNonSpace(&start, limit, theChars);
  328.             while (start <= limit)
  329.             {
  330.                 (*result)++;
  331.                 switch (elementType)
  332.                 {
  333.                     case cWord:
  334.                         MoveToSpace(&start, limit, theChars);
  335.                         break;
  336.                         
  337.                     case cParagraph:
  338.                         MoveToEndOfParagraph(&start, limit, theChars);
  339.                         break;
  340.                 }
  341.                 MoveToNonSpace(&start, limit, theChars);
  342.             }
  343.             break;
  344.     
  345.         default:
  346.             *result = -1;
  347.             err = errAEBadKeyForm;
  348.     }
  349.     
  350.     return(err);
  351. } // CountTextElements
  352.  
  353. OSErr    GetDescOfNthTextElement(short index, DescType elementType,
  354.                                         TextToken* containerToken, AEDesc* result)
  355. {
  356.     DPtr        docPtr;
  357.     TextToken    theToken;
  358.     short        start,
  359.                 maxChars,
  360.                 elementCount,
  361.                 limit,
  362.                 elementStart;
  363.     charsHandle    theChars;
  364.     OSErr        err;
  365.     
  366.     if (! containerToken)
  367.         return(errAEEmptyListContainer);
  368.  
  369.     docPtr = DPtrFromWindowPtr(containerToken->tokenWindow);
  370.     start = containerToken->tokenOffset - 1;    // Zero based
  371.     maxChars = containerToken->tokenLength;
  372.  
  373.     err = CountTextElements(docPtr->theText, containerToken->tokenOffset,
  374.                                         maxChars, elementType, &elementCount);
  375.     if (noErr != err) return(err);
  376.     
  377.     if (index < 0)                        // Change a negative index to positive
  378.         index = elementCount + index + 1;
  379.         
  380.     if (index > elementCount)            // Got given an index out of range
  381.         return(errAEIllegalIndex);
  382.         
  383.             // Set the window that the token relates to
  384.     theToken.tokenWindow = containerToken->tokenWindow;
  385.  
  386.     switch (elementType)
  387.     {
  388.         case cInsertionPoint:
  389.             theToken.tokenOffset = start + index - 1;
  390.             theToken.tokenLength = 0;
  391.             break;
  392.             
  393.         case cChar:        // Easy - just the start point + the index
  394.             theToken.tokenOffset = start + index;
  395.             theToken.tokenLength = 1;
  396.             break;
  397.             
  398.         case cText:    
  399.             theToken.tokenOffset = start + index;
  400.             theToken.tokenLength = maxChars;
  401.             break;
  402.             
  403.         case cWord:
  404.         case cParagraph:
  405.             theChars = (charsHandle)(**(docPtr->theText)).hText;
  406.             limit = start + maxChars - 1;
  407.             MoveToNonSpace(&start, limit, theChars);
  408.             while ((start <= limit) && (index > 0))
  409.             {
  410.                 index--;
  411.                 elementStart = start;
  412.                 switch (elementType)
  413.                 {
  414.                     case cWord:
  415.                         MoveToSpace(&start, limit, theChars);
  416.                         break;
  417.                         
  418.                     case cParagraph:
  419.                         MoveToEndOfParagraph(&start, limit, theChars);
  420.                         break;
  421.                 }
  422.                 theToken.tokenLength = start - elementStart;
  423.                 MoveToNonSpace(&start, limit, theChars);
  424.             }
  425.             theToken.tokenOffset = elementStart + 1;    // Convert to one based
  426.             break;
  427.     }
  428.  
  429.     err = AECreateDesc(typeMyText, (Ptr)&theToken, sizeof(theToken), result);
  430.  
  431.     return(err);
  432. }
  433.  
  434.  
  435. char    GetTEHChar(TEHandle aTEH, short offset)
  436. {
  437.     char    result;
  438.     
  439.     offset--;        // This is now 0 based
  440.  
  441.     if (offset < 0 || offset >= (*aTEH)->teLength)
  442.         return('\0');
  443.         
  444.     result = *(char *)((*(**aTEH).hText) + offset);
  445.     
  446.     return(result);
  447. }
  448.  
  449. Boolean        IsAtStart(TextToken* theToken)
  450. {
  451.     Boolean    result;
  452.                     // Is at start if offset is at 1
  453.     result = (theToken->tokenOffset == 1);
  454.     
  455.     return(result);
  456. }
  457.  
  458. Boolean        IsAtEnd(TextToken* theToken)
  459. {
  460.     TEHandle    aTEH;
  461.     Boolean        result;
  462.     
  463.     aTEH = TEHandleFromTextToken(theToken);
  464.                     // Does it go to the end?
  465.     result = (theToken->tokenOffset + theToken->tokenLength >= (**aTEH).teLength);
  466.     
  467.     return(result);
  468. }
  469.  
  470. Boolean        IsWhiteSpace(short aChar)
  471. {
  472.     Boolean    result;
  473.  
  474.     result = (aChar == ' ' || aChar == ',' || aChar == '.'
  475.                 || aChar == ':' || aChar == LF || aChar == CR);
  476.              
  477.     return(result);
  478. }
  479.  
  480. Boolean        IsParagraphDelimiter(short aChar)
  481. {
  482.     Boolean    result;
  483.  
  484.     result = (aChar == CR);
  485.              
  486.     return(result);
  487. }
  488.  
  489. Boolean        IsContentsToken(TextToken* theToken)
  490. {
  491.     return(IsAtStart(theToken) && IsAtEnd(theToken));
  492. }
  493.  
  494. Boolean        IsParagraphToken(TextToken* theToken, short* start, short* end)
  495. {
  496.     TEHandle    aTEH;
  497.     OSErr        err;
  498.     short        number;
  499.     Boolean        fStart,
  500.                 fEnd,
  501.                 result;
  502.     
  503.     aTEH = TEHandleFromTextToken(theToken);
  504.         
  505.     fStart = IsAtStart(theToken) || IsParagraphDelimiter(GetTEHChar(aTEH, theToken->tokenOffset - 1));
  506.     fEnd = IsAtEnd(theToken) || IsParagraphDelimiter(GetTEHChar(aTEH, theToken->tokenOffset + theToken->tokenLength));
  507.     
  508.     if (fStart && fEnd)
  509.     {
  510.         // need to do a count of the paragraphs
  511.         
  512.         err = CountTextElements(aTEH, theToken->tokenOffset,
  513.                             theToken->tokenLength, cParagraph, &number);
  514.  
  515.         // count text elements before it i.e. offset == 0 limit == theToken->tokenOffset
  516.         
  517.         if (IsAtStart(theToken))
  518.             *start = 1;
  519.         else
  520.         {                // From beginning to charracter before start of paragraph
  521.             err = CountTextElements(aTEH, 1,theToken->tokenOffset - 1, cParagraph, start);
  522.             (*start)++;
  523.         }
  524.         
  525.         *end = *start + number - 1;
  526.         
  527.         result = true;
  528.     }
  529.     else
  530.         result = false;
  531.     
  532.     return(result);
  533. }
  534.  
  535. Boolean        IsWordToken(TextToken* theToken, short* start, short* end)
  536. {
  537.     TEHandle    aTEH;
  538.     OSErr        err;
  539.     short        number;
  540.     Boolean        fStart,
  541.                 fEnd,
  542.                 result;
  543.         
  544.     aTEH = TEHandleFromTextToken(theToken);
  545.         
  546.     fStart = IsAtStart(theToken) || IsWhiteSpace(GetTEHChar(aTEH, theToken->tokenOffset - 1));
  547.     fEnd = IsAtEnd(theToken) || IsWhiteSpace(GetTEHChar(aTEH, theToken->tokenOffset + theToken->tokenLength));
  548.     
  549.     if (fStart && fEnd)
  550.     {
  551.         // need to do a count of the words
  552.         
  553.         err = CountTextElements(aTEH, theToken->tokenOffset,
  554.                             theToken->tokenLength, cWord, &number);
  555.  
  556.         // count text elements before it i.e. offset == 0 limit == theToken->tokenOffset
  557.         
  558.         if (IsAtStart(theToken))
  559.             *start = 1;
  560.         else
  561.         {                // From beginning to charracter before start of word
  562.             err = CountTextElements(aTEH, 1, theToken->tokenOffset - 1, cWord, start);
  563.             (*start)++;
  564.         }
  565.         
  566.         *end = *start + number - 1;
  567.         
  568.         result = true;
  569.     }
  570.     else
  571.         result = false;
  572.     
  573.     return(result);
  574. }
  575.  
  576.  
  577. DescType    GetTextTokenType(TextToken* theToken, short* start, short* end)
  578. {
  579.     DescType    result;
  580.     
  581.     *start = *end = -1;                    // Just set to the same value
  582.  
  583.     if (! theToken->tokenLength)
  584.     {
  585.         result = cInsertionPoint;
  586.     }
  587.     else if (IsContentsToken(theToken))
  588.     {
  589.         result = pContents;
  590.     }
  591.     else if (IsParagraphToken(theToken, start, end))
  592.     {
  593.         result = cParagraph;
  594.     }
  595.     else if (IsWordToken(theToken, start, end))
  596.     {
  597.         result = cWord;
  598.     }
  599.     else
  600.     {
  601.         result = cChar;
  602.         *start = theToken->tokenOffset;
  603.         *end = theToken->tokenOffset + theToken->tokenLength - 1;
  604.     }
  605.     
  606.     return(result);
  607. }
  608.  
  609. OSErr    MakeContentsSpecifier(TextToken* theToken, AEDesc* result)
  610. {
  611.     AEDesc        docSpec = {typeNull, NULL},
  612.                 contentsDesc = {typeNull, NULL};
  613.     DescType    propertyID;
  614.     OSErr        err;
  615.  
  616.     err = MakeDocumentObj(theToken->tokenWindow, &docSpec);
  617.     if (noErr != err) goto done;
  618.     
  619.     propertyID = pContents;
  620.     err = AECreateDesc(typeType, (Ptr)&propertyID, sizeof(DescType), &contentsDesc);
  621.     if (err != noErr) goto done;
  622.     err = CreateObjSpecifier(cProperty, &docSpec, formPropertyID, &contentsDesc, false, result);
  623.  
  624. done:
  625.     (void)AEDisposeDesc(&docSpec);
  626.     (void)AEDisposeDesc(&contentsDesc);
  627.     
  628.     return(err);
  629. }
  630.  
  631.  
  632. OSErr    MakeAbsoluteTextSpecifier(WindowPtr theWindow, DescType textType, long index, AEDesc* result)
  633. {
  634.     AEDesc        docSpec = {typeNull, NULL},
  635.                 absoluteDesc = {typeNull, NULL};
  636.     OSErr        err;
  637.     
  638.     if (theWindow)
  639.     {
  640.         err = MakeDocumentObj(theWindow, &docSpec);
  641.         if (noErr != err) goto done;
  642.     }
  643.     // else just use the NULL'ed value
  644.  
  645.     err = AECreateDesc(typeLongInteger, (Ptr)&index, sizeof(index), &absoluteDesc);
  646.     if (err != noErr) goto done;
  647.     err = CreateObjSpecifier(textType, &docSpec, formAbsolutePosition,
  648.                                                     &absoluteDesc, false, result);
  649.  
  650. done:
  651.     (void)AEDisposeDesc(&docSpec);
  652.     (void)AEDisposeDesc(&absoluteDesc);
  653.     
  654.     return(err);
  655. }
  656.  
  657.  
  658. OSErr    MakeInsertionPointSpecifier(TextToken* theToken, AEDesc* result)
  659. {
  660.     AEDesc        relativeToSpec = {typeNull, NULL},
  661.                 relativeDesc = {typeNull, NULL};
  662.     DescType    relativeType;
  663.     OSErr        err;
  664.  
  665.     if (IsAtStart(theToken))            // Before contents (whether there are any or not)
  666.     {
  667.         relativeType = kAEPrevious;
  668.         err = MakeContentsSpecifier(theToken, &relativeToSpec);
  669.     }
  670.     else if (IsAtEnd(theToken))            // After last character
  671.     {
  672.         relativeType = kAENext;
  673.         //err = MakeContentsSpecifier(theToken, &relativeToSpec);
  674.         err = MakeAbsoluteTextSpecifier(theToken->tokenWindow, cChar, -1, &relativeToSpec);
  675.     }
  676.     else                                // Has a character it can go before
  677.     {
  678.         relativeType = kAEPrevious;
  679.         err = MakeAbsoluteTextSpecifier(theToken->tokenWindow, cChar, theToken->tokenOffset, &relativeToSpec);
  680.     }
  681.  
  682.     if (noErr != err) goto done;
  683.     
  684.       err = AECreateDesc(typeEnumerated, &relativeType, sizeof(relativeType), &relativeDesc);
  685.     if (noErr != err) goto done;
  686.     err = CreateObjSpecifier(cInsertionPoint, &relativeToSpec, formRelativePosition,
  687.                                                                    &relativeDesc, false, result);
  688.  
  689. done:
  690.     (void)AEDisposeDesc(&relativeToSpec);
  691.     (void)AEDisposeDesc(&relativeDesc);
  692.  
  693.     return(err);
  694. }
  695.  
  696. OSErr    GetIndexSpecifier(TextToken* theToken, DescType textType, long index, AEDesc* result)
  697. {
  698.     OSErr    err;
  699.  
  700.     switch (textType)
  701.     {
  702.         case cInsertionPoint:
  703.             err = MakeInsertionPointSpecifier(theToken, result);
  704.             break;
  705.             
  706.         case pContents:
  707.             err = MakeContentsSpecifier(theToken, result);
  708.             break;
  709.             
  710.         case cParagraph:
  711.         case cWord:
  712.         case cChar:
  713.             err = MakeAbsoluteTextSpecifier(theToken->tokenWindow, textType, index, result);
  714.             break;
  715.         
  716.         default:
  717.             err = errAETypeError;
  718.     }
  719.     
  720.     return(err);
  721. }
  722.  
  723.  
  724. OSErr    GetTextTokenObjectSpecifier(TextToken* theToken, AEDesc* result)
  725. {
  726.     AEDesc        docSpec = {typeNull, NULL},
  727.                 startSpec = {typeNull, NULL},
  728.                 endSpec = {typeNull, NULL},
  729.                 rangeDesc = {typeNull, NULL};
  730.     DescType    textType;
  731.     short        start,
  732.                 end;
  733.     OSErr        err;
  734.     
  735.     textType = GetTextTokenType(theToken, &start, &end);
  736.     
  737.     err = GetIndexSpecifier(theToken, textType, start, &startSpec);
  738.     if (noErr != err) goto done;
  739.  
  740.     if (start != end)        // Sort out rest of range specifier
  741.     {
  742.         err = GetIndexSpecifier(theToken, textType, end, &endSpec);
  743.         if (noErr != err) goto done;
  744.         
  745.         err = CreateRangeDescriptor(&startSpec, &endSpec, false, &rangeDesc);
  746.         if (noErr != err) goto done;
  747.  
  748.         err = MakeDocumentObj(theToken->tokenWindow, &docSpec);
  749.         if (noErr != err) goto done;
  750.  
  751.         err = CreateObjSpecifier(cText, &docSpec, formRange, &rangeDesc, false, result);
  752.     }
  753.     else
  754.         err = AEDuplicateDesc(&startSpec, result);
  755.     
  756. done:
  757.     (void)AEDisposeDesc(&docSpec);
  758.     (void)AEDisposeDesc(&startSpec);
  759.     (void)AEDisposeDesc(&endSpec);
  760.     (void)AEDisposeDesc(&rangeDesc);
  761.  
  762.     return(err);
  763. }
  764.